/*-----------------------------------------------------------------------------
	The contents of this file are subject to the Mozilla Public License
	Version 1.1 (the "License"); you may not use this file except in
	compliance with the License. You may obtain a copy of the License at
	http://www.mozilla.org/MPL/
	
	Software distributed under the License is distributed on an "AS IS"
	basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
	License for the specific language governing rights and limitations
	under the License.
	
	The Original Code is Fever Framework code.
	
	The Initial Developer of the Original Code is Romain Ecarnot.
	Portions created by Initial Developer are Copyright (C) 2006
	the Initial Developer. All Rights Reserved.
	
	Contributor(s):
	
	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License.
-----------------------------------------------------------------------------*/

import com.bourre.events.EventBroadcaster;
import com.bourre.events.EventType;
import com.bourre.events.IEvent;
import com.bourre.events.StringEvent;

import fever.conf.ParserQueueListener;
import fever.conf.parsers.ConfigurationParser;
import fever.structures.ProtectedQueue;
import fever.structures.QueueProtectionType;

/**
 * Queue structure to store configuration parser.
 * 
 * <p>Used by the {@link fever.conf.Configuration} class only.
 * 
 * <p>You can customize configuration parsing using {@link #addType()} method.
 * 
 * <p>Events support : 
 * <ul>
 *   <li>{@link #onParsingStartEVENT}</li>
 *   <li>{@link #onParsingChangeEVENT}</li> *   <li>{@link #onParsingCompleteEVENT}</li>
 * </ul>
 * 
 * @see fever.conf.Configuration
 *
 * @author Romain Ecarnot
 */
class fever.conf.ParserQueue
{
	//-------------------------------------------------------------------------
	// Events definition
	//-------------------------------------------------------------------------
	
	/** Broadcasted when configuration parsing starts. */
	public static var onParsingStartEVENT : EventType = new EventType( 'onParsingStart' );
	 
	/**
	 * Broadcasted when a new {@link fever.conf.parsers.ConfigurationParser} parser type 
	 * starts confiuration parsing.
	 */	public static var onParsingChangeEVENT : EventType = new EventType( 'onParsingChange' );
	
	/**
	 * Broadcasted when a new {@link fever.conf.parsers.LibParser} parser type 
	 * progress.
	 */
	public static var onParsingProgressEVENT : EventType = new EventType( 'onParsingProgress' );
	
	
	/** Broadcasted when configuration parsing is complete. */ 	public static var onParsingCompleteEVENT : EventType = new EventType( 'onParsingComplete' );
	
		
	//-------------------------------------------------------------------------
	// Private properties
	//-------------------------------------------------------------------------
	
	private var _q : ProtectedQueue;
	private var _parser : ConfigurationParser;
	private var _oEB : EventBroadcaster;
	private var _isRunning : Boolean;
	
	
	//-------------------------------------------------------------------------
	// Public API
	//-------------------------------------------------------------------------
	
	/**
	 * Constructor.
	 */
	public function ParserQueue()
	{
		_q = new ProtectedQueue( QueueProtectionType.TYPE );
		_oEB = new EventBroadcaster( this );
		
		_isRunning = false;
	}
	
	/**
	 * Adds passed-in {@code parser} as configuration parser.
	 * 
	 * @param parser A {@link fever.conf.parsers.ConfigurationParser} instance
	 */
	public function addType( parser : ConfigurationParser ) : Void
	{
		if( !_isRunning ) _q.enqueue( parser );
	}
	
	/**
	 * Removes passed-in {@code parser} from configuration parser list.
	 * 
	 * @param parser A {@link fever.conf.parsers.ConfigurationParser} instance
	 */
	public function removeType( parser : ConfigurationParser ) : Void
	{
		if( !_isRunning ) _q.remove( parser );
	}
	
	/**
	 * Starts process.
	 * 
	 * <p>If a parsing is already running, do nothing.
	 */
	public function execute() : Void
	{
		if ( !isEmpty() && !_isRunning )
		{
			_fireEvent( onParsingStartEVENT, 'parsing configuration' );
			_isRunning = true;
			_parseNext();
		}
	}
	
	/**
	 * Returns {@code true} if parser queue is empty.
	 */
	public function isEmpty() : Boolean
	{
		return _q.isEmpty();
	}
	
	/**
	 * Returns {@code true} if parsing process is running.
	 */
	public function isRunning() : Boolean
	{
		return _isRunning;	
	}
	
	/**
	 * Adds passed-in {@code listener} for receiving all events.
	 * 
	 * @param listener {@link fever.conf.ParserQueueListener}
	 */
	public function addListener( listener : ParserQueueListener ) : Void
	{
		_oEB.addListener( listener );
	}
	
	/**
	 * Removes passed-in {@code listener} for receiving all events.
	 * 
	 * @param listener {@link fever.conf.ParserQueueListener}
	 */
	public function removeListener( listener : ParserQueueListener ) : Void
	{
		_oEB.removeListener( listener );
	}
	
	/**
	 * Triggered by the internal process to indicate that a new 
	 * {@link fever.conf.parsers.ConfigurationParser} parser starts parsing.
	 */
	public function onParserStart( event : IEvent ) : Void
	{
		_fireEvent( onParsingChangeEVENT, ConfigurationParser( event.getTarget() ).getParsingLabel() );
	}
	
	/**
	 * Triggered by the internal process to indicate that a new 
	 * {@link fever.conf.parsers.ConfigurationParser} parser starts parsing.
	 */
	public function onParserUpdate( event : IEvent ) : Void
	{
		_fireEvent( onParsingChangeEVENT, ConfigurationParser( event.getTarget() ).getParsingLabel() );
	}
	
	/**
	 * Triggered by the internal process to indicate that a new 
	 * {@link fever.conf.parsers.LibParser} parser progress.
	 */
	public function onParserProgress( event : StringEvent ) : Void
	{
		_fireEvent( onParsingProgressEVENT, ConfigurationParser( event.getTarget() ).getParsingLabel() + event.getString() );
	}
	
	/**
	 * Triggered by the internal process to indicate that a parser has finished 
	 * is job.
	 * 
	 * <p>Checks the queue to know if other parser must be execute.
	 */
	public function onParserComplete( event : IEvent ) : Void
	{
		_release();
		
		_checkQueue();
	}
	
	
	//-------------------------------------------------------------------------
	// Private implementation
	//-------------------------------------------------------------------------
	
	private function _parseNext() : Void
	{
		_parser = ConfigurationParser( _q.dequeue() );
		_parser.addListener( this );
		_parser.parse();
	}
	
	private function _checkQueue() : Void
	{
		if( !isEmpty() ) _parseNext();
		else _complete();
	}
	
	private function _release() : Void
	{
		if( _parser != undefined ) _parser.removeListener( this );
	}
	
	private function _complete() : Void
	{
		_release();
		_fireEvent( onParsingCompleteEVENT, 'initialisation' );
	}
	
	private function _fireEvent( type : EventType, caption : String ) : Void
	{
		_oEB.broadcastEvent( new StringEvent( type, caption ) );	
	}
}